package gates;
import java.awt.Graphics;
import java.util.*;

import master.*;




/**
 * @author Oliver Wiese
 *			
 *
 */
public class ToffoliGate implements QuantumGate{

	public static IllegalArgumentException GateException =
			new IllegalArgumentException("applying wrong type of gate to register");



	@Override
	public boolean checkDim(QuantumRegister register)
			throws IllegalArgumentException {
		return false;
	}

	@Override
	public QuantumRegister actOnReg(QuantumRegister register, int bit1) {
		throw GateException;
	}



	@Override
	public QuantumRegister actOnReg(QuantumRegister register, int bit1, int bit2) {
		throw GateException;
	}



	@Override
	public QuantumRegister actOnReg(QuantumRegister register, int control1,	int control2, int target) {
			
		List<Integer> mem = new LinkedList<Integer>(); // list to hold states
	
		for (int t = 0; t < register.getDimension(); t++) { // loop over all basis states
			// if the bits (j1-1) and (j2-1) are not met by t, then go on...
			

			//compare if the current state has a 1 where the first control bit has a 1 and store the control state 
			int a = (t & power2(control1-1));
			//compare for the second bit and store the control state
			int b = (t & power2(control2-1));
			//sum of the 2 control bit states
			int c = power2(control1 - 1) + power2(control2 - 1);

			// if the control bits are not met in the current state the continue the search 
			if ( a + b < c ) {
				continue;
			}
			// if they are met collect all states that have a zero where the target bit is
			int e = t - power2(target-1);
			if (!mem.contains(e)) {
				mem.add(t);
			}
		}

		
		ComplexNumber temp;
		// exchange the stored indices:
		int t2;
		for ( int t : mem) { // loop over the collected states
			
			// find state that has only the target bit changed to 1
			if(t + power2(target-1) < register.getDimension()) {
				t2 = t + power2(target-1); 
			}else{
				t2 = t - power2(target-1);
			}
			// exchange the coefficients of the states that are affected
			temp = register.getCoefficient(t);
			register.setCoefficient(register.getCoefficient(t2), t);
			register.setCoefficient(temp, t2);

		}
		return register;
	}


	//*
	@Override
	public QuantumGate multiply(QuantumGate gate) {
		// TODO Auto-generated method stub
		return null;
	}
//*/

	public int power2( int n ) {
		return 1 << n;
	}
	
	// small method for printing out registers
	public static void printOut(QuantumRegister reg){
		for (int n=reg.getDimension()-1;n>=0;n--){
			System.out.print("|" + reg.getCoefficient(n) + ">");
		}
		System.out.println("");
	}
	
//*
	
	// small test code to see it works
	public static void main(String[] args){
		QuantumRegister reg = new QuantumRegister(5);
		QuantumGate tgate = new ToffoliGate();
		reg.setToEigenstate(24);
		printOut(reg);
		reg = tgate.actOnReg(reg, 5, 4, 2);
		printOut(reg);

	}
//*/

	@Override
	public void draw(Graphics g, int x, int y, float scale) {
		// TODO Auto-generated method stub
		
	}

}
